package com.java80.littlegame.common.db.dao.base;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.java80.littlegame.common.db.utils.DBConnectionFactory;

public abstract class BaseDao {
	public static void main(String[] args) throws SQLException {
		/*
		 * DBConnectionFactory.init(); List<UUserInfo> find = new
		 * BaseDao().find("select * from u_user_info where id=?",
		 * Arrays.asList(1), UUserInfo.class); for (UUserInfo uUserInfo : find)
		 * { System.out.println("uUserInfo->" +
		 * GsonUtil.parseObject(uUserInfo)); }
		 */
	}

	public void insert(String sql, List<Object> params) throws SQLException {

		Connection con = DBConnectionFactory.getConnection();
		PreparedStatement ps = null;
		try {
			ps = con.prepareStatement(sql);
			for (int i = 0; i < params.size(); i++) {
				ps.setObject(i + 1, params.get(i));
			}
			ps.execute();
		} finally {
			try {
				ps.close();
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void insertBatch(String sql, List<List<Object>> params) throws SQLException {
		updateBatch(sql, params);
	}

	public void delete(String sql, List<Object> params) throws SQLException {
		update(sql, params);
	}

	public void deleteBatch(String sql, List<List<Object>> params) throws SQLException {
		updateBatch(sql, params);
	}

	public <T> T get(String sql, List<Object> params, Class<T> clazz) throws Exception {
		List<T> find = find(sql, params, clazz);
		if (find != null && find.size() == 1) {
			return find.get(0);
		}
		return null;
	}

	public <T> List<T> find(String sql, List<Object> params, Class<T> clazz) throws Exception {
		Connection con = DBConnectionFactory.getConnection();
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = con.prepareStatement(sql);
			if (params != null)
				for (int i = 0; i < params.size(); i++) {
					ps.setObject(i + 1, params.get(i));
				}
			rs = ps.executeQuery();
			List<Field> fieldList = new ArrayList<>();
			Class<?> t = clazz;
			while (t != null) {// 当父类为null的时候说明到达了最上层的父类(Object类).
				fieldList.addAll(Arrays.asList(t.getDeclaredFields()));
				t = t.getSuperclass();
				if (t.getName().equals(Object.class.getName())) {
					break;
				}
			}
			List<T> result = new ArrayList<>();
			while (rs.next()) {
				Object o = clazz.newInstance();
				for (Field field : fieldList) {
					String f = field.getName();
					f = f.substring(0, 1).toUpperCase() + f.substring(1);
					Method method = clazz.getMethod("set" + f, field.getType());
					method.invoke(o, rs.getObject((f)));
				}
				result.add((T) o);
			}

			return result;
		} finally {
			try {
				rs.close();
				ps.close();
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	public void updateBatch(String sql, List<List<Object>> params) throws SQLException {
		Connection con = DBConnectionFactory.getConnection();
		PreparedStatement ps = null;
		try {
			con.setAutoCommit(false);
			ps = con.prepareStatement(sql);
			for (int i = 0; i < params.size(); i++) {
				List<Object> list = params.get(i);
				for (int j = 0; j < list.size(); j++) {
					ps.setObject(j + 1, list.get(j));
				}
				if ((i + 1) % 300 == 0) {
					ps.executeBatch();
				}
			}
			// 若总条数不是批量数值的整数倍, 则还需要再额外的执行一次.
			if (params.size() % 300 != 0) {
				ps.executeBatch();
			}
			con.commit();
		} finally {
			try {
				ps.close();
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void update(String sql, List<Object> params) throws SQLException {

		Connection con = DBConnectionFactory.getConnection();
		PreparedStatement ps = null;
		try {
			ps = con.prepareStatement(sql);
			for (int i = 0; i < params.size(); i++) {
				ps.setObject(i + 1, params.get(i));
			}
			ps.executeUpdate();
		} finally {
			try {
				ps.close();
				con.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
